<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Java并发体系-第三阶段-JUC并发包-[1] | 风祈的时光录</title><meta name="keywords" content="Java并发，原理，源码"><meta name="author" content="youthlql"><meta name="copyright" content="youthlql"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="万字系列长文讲解-Java并发体系-第三阶段-JUC并发包。JUC在高并发编程中使用频率非常高，这里会详细介绍其用法。">
<meta property="og:type" content="article">
<meta property="og:title" content="Java并发体系-第三阶段-JUC并发包-[1]">
<meta property="og:url" content="https://imlql.cn/post/5be45d9e.html">
<meta property="og:site_name" content="风祈的时光录">
<meta property="og:description" content="万字系列长文讲解-Java并发体系-第三阶段-JUC并发包。JUC在高并发编程中使用频率非常高，这里会详细介绍其用法。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png">
<meta property="article:published_time" content="2020-10-09T14:13:58.000Z">
<meta property="article:modified_time" content="2022-07-24T11:02:09.800Z">
<meta property="article:author" content="youthlql">
<meta property="article:tag" content="Java并发">
<meta property="article:tag" content="原理">
<meta property="article:tag" content="源码">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png"><link rel="shortcut icon" href="https://npm.elemecdn.com/youthlql@1.0.8/blog/favicon.png"><link rel="canonical" href="https://imlql.cn/post/5be45d9e"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://npm.elemecdn.com/@fortawesome/fontawesome-free@6/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/@fancyapps/ui/dist/fancybox.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?f693ff99cc7e613b88cf5b729a14b48b";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Java并发体系-第三阶段-JUC并发包-[1]',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-07-24 19:02:09'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><link rel="stylesheet" href="https://npm.elemecdn.com/lql_static@latest/butterfly_static/css/ali_icon.css"><link rel="stylesheet" href="https://npm.elemecdn.com/lql_static@latest/butterfly_static/css/2-24-mogai.css"><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="风祈的时光录" type="application/atom+xml">
</head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/avatar/2.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data is-center"><div class="data-item"><a href="/archives/"><div class="headline">文章</div><div class="length-num">37</div></a></div><div class="data-item"><a href="/tags/"><div class="headline">标签</div><div class="length-num">21</div></a></div><div class="data-item"><a href="/categories/"><div class="headline">分类</div><div class="length-num">13</div></a></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw iconfont icon-shouyex"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw iconfont icon-zuixinwenzhang_huaban"></i><span> 找文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw iconfont icon-fenlei1"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw iconfont icon-biaoqian1"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw iconfont icon-shijianzhou"></i><span> 归档</span></a></li></ul></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">风祈的时光录</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw iconfont icon-shouyex"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw iconfont icon-zuixinwenzhang_huaban"></i><span> 找文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw iconfont icon-fenlei1"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw iconfont icon-biaoqian1"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw iconfont icon-shijianzhou"></i><span> 归档</span></a></li></ul></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Java并发体系-第三阶段-JUC并发包-[1]</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2020-10-09T14:13:58.000Z" title="发表于 2020-10-09 22:13:58">2020-10-09</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-24T11:02:09.800Z" title="更新于 2022-07-24 19:02:09">2022-07-24</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java%E5%B9%B6%E5%8F%91/">Java并发</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java%E5%B9%B6%E5%8F%91/%E5%8E%9F%E7%90%86/">原理</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">9.9k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>41分钟</span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="AtomicXXXFieldUpdater"><a href="#AtomicXXXFieldUpdater" class="headerlink" title="AtomicXXXFieldUpdater"></a>AtomicXXXFieldUpdater</h1><blockquote>
<p>算是一个小补充</p>
</blockquote>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AtomicIntegerFieldUpdaterTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        AtomicIntegerFieldUpdater&lt;Test&gt; updater = AtomicIntegerFieldUpdater.newUpdater(Test.class, <span class="string">&quot;value&quot;</span>);</span><br><span class="line">        Test ts = <span class="keyword">new</span> Test();</span><br><span class="line"></span><br><span class="line">        IntStream.rangeClosed(<span class="number">0</span>, <span class="number">2</span>).forEach(item -&gt; &#123;            </span><br><span class="line">        	<span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">int</span> value = updater.getAndIncrement(ts);</span><br><span class="line">                System.out.println(<span class="string">&quot;oldV: &quot;</span> + value);</span><br><span class="line">            &#125;).start();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test</span> </span>&#123;</span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>1、以<code>AtomicIntegerFieldUpdater</code>为例，看上面代码。Test类的value属性被volatile修饰了，但是volatile只能保证可见性和有序性。在以往的文章里我们讲过是可以通过volatile+CAS同时解决可见性，有序性，原子性。</p>
<p>2、JUC提供了一种新的功能来保证原子性，AtomicXXXFieldUpdater修饰的类对应的字段，在进行更新时同样可以保证原子性。</p>
<h2 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h2><ul>
<li><p>想让类的属性操作具备原子性，</p>
</li>
<li><p>但是不想使用锁。</p>
</li>
<li><p>大量需要原子类型修饰的对象，相比较比较耗费内存</p>
</li>
</ul>
<p>举个例子：</p>
<p>如果你想要保证原子性，一般是使用<code>AtomicStampedReference&lt;Node&gt;</code>来包装Node对象。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.lucene.util.RamUsageEstimator;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicStampedReference;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/10/11 16:51</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述: 计算对象内存大小</span></span><br><span class="line"><span class="comment"> * https://blog.csdn.net/yunqiinsight/article/details/80431831</span></span><br><span class="line"><span class="comment"> * https://www.cnblogs.com/libin6505/p/10648091.html</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Calculate_Java_Object_Size</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Node node = <span class="keyword">new</span> Node();</span><br><span class="line">        <span class="comment">//计算指定对象本身在堆空间的大小，单位字节</span></span><br><span class="line">        <span class="keyword">long</span> b = RamUsageEstimator.shallowSizeOf(node);</span><br><span class="line">        System.out.println(b);</span><br><span class="line"></span><br><span class="line">        AtomicStampedReference&lt;Node&gt; nodeAtomicStampedReference = <span class="keyword">new</span> AtomicStampedReference&lt;Node&gt;(node,<span class="number">0</span>);</span><br><span class="line">        <span class="keyword">long</span> c = RamUsageEstimator.shallowSizeOf(nodeAtomicStampedReference);</span><br><span class="line">        System.out.println(c + b);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 功能描述: Api说明</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Api</span><span class="params">(Object o)</span></span>&#123;</span><br><span class="line">        <span class="comment">//下面三个方法参数都是 Object类型</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//计算指定对象及其引用树上的所有对象的综合大小，单位字节</span></span><br><span class="line">        <span class="keyword">long</span> a = RamUsageEstimator.sizeOf(o);</span><br><span class="line">        System.out.println(a);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//计算指定对象本身在堆空间的大小，单位字节</span></span><br><span class="line">        <span class="keyword">long</span> b = RamUsageEstimator.shallowSizeOf(o);</span><br><span class="line">        System.out.println(b);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//计算指定对象及其引用树上的所有对象的综合大小，返回可读的结果，如：2KB</span></span><br><span class="line">        String c = RamUsageEstimator.humanSizeOf(o);</span><br><span class="line">        System.out.println(c);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">    Node pre;</span><br><span class="line">    Node next;</span><br><span class="line">    Integer value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<blockquote>
<p>输出结果：</p>
<p>24</p>
<p>40</p>
</blockquote>
<p>可以看出如果用了<code>AtomicStampedReference&lt;Node&gt;</code>，会多出16个字节。如果对象有10000个，那么会多出很多字节。生产过程中的内存都是很贵的。为了减少内存消耗，同时可以保证原子性，就可以使用<code>AtomicXXXFieldUpdater</code>。</p>
<h1 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h1><h2 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h2><ul>
<li>countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。</li>
<li>是通过一个 state（相当于计数器）的东西来实现的，计数器的初始值是 <strong>线程的数量或者任务的数量</strong>。</li>
<li>每当一个线程执行完毕后，计数器的值就-1，当计数器的值为0时，表示所有线程都执行完毕，然后在闭锁上等待的线程就可以恢复工作了。</li>
<li>CountDownLatch的方便之处在于，你可以在一个线程中使用， <strong>也可以在多个线程上使用，一切只依据状态值</strong>，这样便不会受限于任何的场景。</li>
</ul>
<h2 id="使用场景一"><a href="#使用场景一" class="headerlink" title="使用场景一"></a>使用场景一</h2><p><strong>需求</strong></p>
<ul>
<li>可能刚从数据库读取了一批数据</li>
<li>利用并发处理这批数据</li>
<li>当所有的数据处理完成后，再去执行后面的操作</li>
</ul>
<p><strong>解决方案</strong></p>
<ul>
<li><strong>第一种</strong>：可以利用 join 的方法，但是在线程池中，比较麻烦。</li>
<li><strong>第二种</strong>：利用线程池的awaitTermination，阻塞一段时间。<ul>
<li>当使用awaitTermination时，主线程会处于一种等待的状态，等待线程池中所有的线程都运行完毕后才继续运行。</li>
</ul>
</li>
<li><strong>第三种</strong>：利用CountDownLatch，每当任务完成一个，就计数器减一。</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> _05_AQS;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CountDownLatch;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 10:05</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video32</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        CountDownLatch countDownLatch = <span class="keyword">new</span> CountDownLatch(<span class="number">6</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++) &#123;</span><br><span class="line">             <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;\t\t&quot;</span> + Thread.currentThread().getName() + <span class="string">&quot;处理完毕~~~&quot;</span>);</span><br><span class="line">                countDownLatch.countDown();</span><br><span class="line">                System.out.println(<span class="string">&quot;非调用者线程-&quot;</span> + Thread.currentThread().getName() + <span class="string">&quot;-还可以干点其他事&quot;</span>);</span><br><span class="line">             &#125;, Country.forEach_Country(i + <span class="number">1</span>).getCountryName()).start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        countDownLatch.await();</span><br><span class="line">        System.out.println(<span class="string">&quot;-----------------------------&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;\t 所有任务都已经处理完毕，可以往后执行了！&quot;</span>);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Country</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    ONE(<span class="number">1</span>,<span class="string">&quot;1号任务&quot;</span>),</span><br><span class="line">    TWO(<span class="number">2</span>,<span class="string">&quot;2号任务&quot;</span>),</span><br><span class="line">    THREE(<span class="number">3</span>,<span class="string">&quot;3号任务&quot;</span>),</span><br><span class="line">    FOUR(<span class="number">4</span>,<span class="string">&quot;4号任务&quot;</span>),</span><br><span class="line">    FIVE(<span class="number">5</span>,<span class="string">&quot;5号任务&quot;</span>),</span><br><span class="line">    SIX(<span class="number">6</span>,<span class="string">&quot;6号任务&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Integer index;</span><br><span class="line">    <span class="keyword">private</span> String countryName;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Country <span class="title">forEach_Country</span><span class="params">(Integer index)</span></span>&#123;</span><br><span class="line">        Country[] values = Country.values();</span><br><span class="line">        <span class="keyword">for</span> (Country c: values) &#123;</span><br><span class="line">            <span class="keyword">if</span>(c.getIndex() == index)&#123;</span><br><span class="line">                <span class="keyword">return</span> c;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Country(Integer index, String countryName) &#123;</span><br><span class="line">        <span class="keyword">this</span>.index = index;</span><br><span class="line">        <span class="keyword">this</span>.countryName = countryName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Integer <span class="title">getIndex</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> index;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getCountryName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> countryName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>结果</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">		<span class="number">1</span>号任务处理完毕~~~</span><br><span class="line">		<span class="number">5</span>号任务处理完毕~~~</span><br><span class="line">非调用者线程-<span class="number">5</span>号任务-还可以干点其他事</span><br><span class="line">		<span class="number">6</span>号任务处理完毕~~~</span><br><span class="line">		<span class="number">3</span>号任务处理完毕~~~</span><br><span class="line">非调用者线程-<span class="number">3</span>号任务-还可以干点其他事</span><br><span class="line">		<span class="number">4</span>号任务处理完毕~~~</span><br><span class="line">		<span class="number">2</span>号任务处理完毕~~~</span><br><span class="line">非调用者线程-<span class="number">4</span>号任务-还可以干点其他事</span><br><span class="line">非调用者线程-<span class="number">6</span>号任务-还可以干点其他事</span><br><span class="line">非调用者线程-<span class="number">1</span>号任务-还可以干点其他事</span><br><span class="line">-----------------------------</span><br><span class="line">	 所有任务都已经处理完毕，可以往后执行了！</span><br><span class="line">非调用者线程-<span class="number">2</span>号任务-还可以干点其他事</span><br></pre></td></tr></table></figure>

<p>因为countdown只会阻塞调用者，其它线程干完任务就可以干其他事。这里的调用者线程就是main线程。</p>
<h2 id="使用场景二"><a href="#使用场景二" class="headerlink" title="使用场景二"></a>使用场景二</h2><p><strong>需求</strong></p>
<ul>
<li>多个线程协同工作</li>
<li>多个线程需要等待其他线程的工作之后，再进行其后续工作。</li>
<li>被唤醒后继续执行其他操作</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CountDownLatchExample</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> CountDownLatch latch = <span class="keyword">new</span> CountDownLatch(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; Do some initial working.&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                latch.await();</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; Do other working.&quot;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; Do some initial working.&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                latch.await();</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; Do other working.&quot;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;asyn prepare for some data.&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;Data prepare for done.&quot;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                latch.countDown();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>结果</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Thread-<span class="number">0</span> Do some initial working.</span><br><span class="line">Thread-<span class="number">1</span> Do some initial working.</span><br><span class="line">asyn prepare <span class="keyword">for</span> some data.</span><br><span class="line">Data prepare <span class="keyword">for</span> done.</span><br><span class="line">Thread-<span class="number">0</span> Do other working.</span><br><span class="line">Thread-<span class="number">1</span> Do other working.</span><br></pre></td></tr></table></figure>

<p>总体来说意思都差不多</p>
<h2 id="常用API"><a href="#常用API" class="headerlink" title="常用API"></a>常用API</h2><p><strong>构造方法只有一个</strong></p>
<ul>
<li><code>CountDownLatch(int count)</code> ：构造一个以给定计数</li>
</ul>
<p><strong>实例方法</strong></p>
<ul>
<li><code>public void await()</code><ul>
<li><strong>当前线程等到锁存器计数到零</strong></li>
<li>可以被 <strong>打断</strong></li>
</ul>
</li>
<li><code>public boolean await(long timeout,TimeUnit unit)</code><ul>
<li>等待一段时间</li>
<li><strong>timeout</strong> - 等待的最长时间 ， <strong>unit</strong> - timeout参数的时间单位</li>
<li>如果 <strong>指定的等待时间过去</strong>，则返回值false</li>
<li>如果 <strong>计数达到零</strong>，则方法返回值为true</li>
</ul>
</li>
<li><code>public void countDown()</code><ul>
<li>减少锁存器的计数， <strong>如果计数达到零，释放所有等待的线程</strong>。</li>
</ul>
</li>
<li><code>public long getCount()</code><ul>
<li>返回当前计数</li>
</ul>
</li>
</ul>
<h2 id="给离散的平行任务增加逻辑层次关系"><a href="#给离散的平行任务增加逻辑层次关系" class="headerlink" title="给离散的平行任务增加逻辑层次关系"></a>给离散的平行任务增加逻辑层次关系</h2><p><strong>需求</strong></p>
<ul>
<li>并发的从很多的数据库读取大量数据</li>
<li>在读取数据的过程中，某个表可能会出现： 数据丢失、数据精度丢失、数据大小不匹配。</li>
<li>需要进行对数据的各个情况进行检测，这个检测是并发的完成的</li>
<li>所以需要控制如果一个表所有的情况检测完成，再进行后续的操作</li>
</ul>
<p><strong>解决</strong></p>
<ul>
<li>利用 <code>CountDownLatch</code>的计数器</li>
<li>每当一个检测完成，计数器减一</li>
<li>如果计数为0，执行后面操作</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Random;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CountDownLatch;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/10/11 21:05</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Random RANDOM = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="comment">//2个事件请求，这里只演示校验数据行，和数据schema</span></span><br><span class="line">        Event[] events = &#123;<span class="keyword">new</span> Event(<span class="number">1</span>), <span class="keyword">new</span> Event(<span class="number">2</span>)&#125;;</span><br><span class="line"></span><br><span class="line">        ExecutorService service = Executors.newFixedThreadPool(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (Event event : events) &#123;</span><br><span class="line">            <span class="comment">//2个事件请求中，可能涉及多个表，可以再分成多个表</span></span><br><span class="line">            List&lt;Table&gt; tables = capture(event);</span><br><span class="line">            <span class="keyword">for</span> (Table table : tables) &#123;</span><br><span class="line">                TaskBatch taskBatch = <span class="keyword">new</span> TaskBatch(<span class="number">2</span>);</span><br><span class="line">                TrustSourceColumns sourceColumns = <span class="keyword">new</span> TrustSourceColumns(table, taskBatch);</span><br><span class="line">                TrustSourceRecordCount recordCount = <span class="keyword">new</span> TrustSourceRecordCount(table, taskBatch);</span><br><span class="line">                service.submit(sourceColumns);</span><br><span class="line">                service.submit(recordCount);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Event</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> id;</span><br><span class="line"></span><br><span class="line">        Event(<span class="keyword">int</span> id) &#123;</span><br><span class="line">            <span class="keyword">this</span>.id = id;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">interface</span> <span class="title">Watcher</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">done</span><span class="params">(Table table)</span></span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TaskBatch</span> <span class="keyword">implements</span> <span class="title">Watcher</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> CountDownLatch latch;</span><br><span class="line"></span><br><span class="line">        TaskBatch(<span class="keyword">int</span> size) &#123;</span><br><span class="line">            <span class="keyword">this</span>.latch = <span class="keyword">new</span> CountDownLatch(size);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">(Table table)</span> </span>&#123;</span><br><span class="line">            latch.countDown();</span><br><span class="line">            <span class="keyword">if</span> (latch.getCount() == <span class="number">0</span>) &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;The table &quot;</span> + table.tableName + <span class="string">&quot; finished work , &quot;</span> + table.toString());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Table</span> </span>&#123;</span><br><span class="line">        String tableName;</span><br><span class="line">        <span class="keyword">long</span> sourceRecordCount;</span><br><span class="line">        <span class="keyword">long</span> targetCount;</span><br><span class="line">        String columnSchema = <span class="string">&quot;columnXXXType = varchar&quot;</span>;</span><br><span class="line"></span><br><span class="line">        String targetColumnSchema = <span class="string">&quot;&quot;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Table</span><span class="params">(String tableName, <span class="keyword">long</span> sourceRecordCount)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.tableName = tableName;</span><br><span class="line">            <span class="keyword">this</span>.sourceRecordCount = sourceRecordCount;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;Table&#123;&quot;</span> +</span><br><span class="line">                    <span class="string">&quot;tableName=&#x27;&quot;</span> + tableName + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                    <span class="string">&quot;, sourceRecordCount=&quot;</span> + sourceRecordCount +</span><br><span class="line">                    <span class="string">&quot;, targetCount=&quot;</span> + targetCount +</span><br><span class="line">                    <span class="string">&quot;, columnSchema=&#x27;&quot;</span> + columnSchema + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                    <span class="string">&quot;, targetColumnSchema=&#x27;&quot;</span> + targetColumnSchema + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                    <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> List&lt;Table&gt; <span class="title">capture</span><span class="params">(Event event)</span> </span>&#123;</span><br><span class="line">        List&lt;Table&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            list.add(<span class="keyword">new</span> Table(<span class="string">&quot;table-&quot;</span> + event.id + <span class="string">&quot;-&quot;</span> + i, i * <span class="number">1000</span>));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> list;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//校验数据行数是否一致</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TrustSourceRecordCount</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Table table;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> TaskBatch taskBatch;</span><br><span class="line"></span><br><span class="line">        TrustSourceRecordCount(Table table, TaskBatch taskBatch) &#123;</span><br><span class="line">            <span class="keyword">this</span>.table = table;</span><br><span class="line">            <span class="keyword">this</span>.taskBatch = taskBatch;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(RANDOM.nextInt(<span class="number">100</span>));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            table.targetCount = table.sourceRecordCount;</span><br><span class="line"></span><br><span class="line">            taskBatch.done(table);</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//校验数据列属性以及对应的表</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TrustSourceColumns</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Table table;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> TaskBatch taskBatch;</span><br><span class="line"></span><br><span class="line">        TrustSourceColumns(Table table, TaskBatch taskBatch) &#123;</span><br><span class="line">            <span class="keyword">this</span>.table = table;</span><br><span class="line">            <span class="keyword">this</span>.taskBatch = taskBatch;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Thread.sleep(RANDOM.nextInt(<span class="number">100</span>));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            table.targetColumnSchema = table.columnSchema;</span><br><span class="line"></span><br><span class="line">            taskBatch.done(table);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>结果</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">The table table-1-1 finished work , Table&#123;tableName&#x3D;&#39;table-1-1&#39;, sourceRecordCount&#x3D;1000, targetCount&#x3D;1000, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-1-0 finished work , Table&#123;tableName&#x3D;&#39;table-1-0&#39;, sourceRecordCount&#x3D;0, targetCount&#x3D;0, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-2-0 finished work , Table&#123;tableName&#x3D;&#39;table-2-0&#39;, sourceRecordCount&#x3D;0, targetCount&#x3D;0, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-1-2 finished work , Table&#123;tableName&#x3D;&#39;table-1-2&#39;, sourceRecordCount&#x3D;2000, targetCount&#x3D;2000, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-1-3 finished work , Table&#123;tableName&#x3D;&#39;table-1-3&#39;, sourceRecordCount&#x3D;3000, targetCount&#x3D;3000, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-2-1 finished work , Table&#123;tableName&#x3D;&#39;table-2-1&#39;, sourceRecordCount&#x3D;1000, targetCount&#x3D;1000, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-2-2 finished work , Table&#123;tableName&#x3D;&#39;table-2-2&#39;, sourceRecordCount&#x3D;2000, targetCount&#x3D;2000, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line">The table table-2-3 finished work , Table&#123;tableName&#x3D;&#39;table-2-3&#39;, sourceRecordCount&#x3D;3000, targetCount&#x3D;3000, columnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;, targetColumnSchema&#x3D;&#39;columnXXXType &#x3D; varchar&#39;&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="利用CountDownLatch实现回调函数"><a href="#利用CountDownLatch实现回调函数" class="headerlink" title="利用CountDownLatch实现回调函数"></a>利用CountDownLatch实现回调函数</h2><p><strong>实现：</strong></p>
<ul>
<li>在每个线程使计数器减一的时候，利用getCount判断，当前是否所有线程任务执行完成</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CyclicBarrierTest</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyCountDownLatch</span> <span class="keyword">extends</span> <span class="title">CountDownLatch</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Runnable runnable;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">MyCountDownLatch</span><span class="params">(<span class="keyword">int</span> count,Runnable runnable)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(count);</span><br><span class="line">            <span class="keyword">this</span>.runnable = runnable;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">countDown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>.countDown();</span><br><span class="line">            <span class="keyword">if</span> (getCount()==<span class="number">0</span>)&#123;</span><br><span class="line">                <span class="keyword">this</span>.runnable.run();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">final</span> MyCountDownLatch latch = <span class="keyword">new</span> MyCountDownLatch(<span class="number">2</span>, ()-&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;All of work finish done. This is call back.&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                    latch.countDown();</span><br><span class="line">                    System.out.println(getName() +  <span class="string">&quot; finished.&quot;</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;.start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                    latch.countDown();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(getName() +  <span class="string">&quot; finished.&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;.start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h1 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h1><h2 id="引出"><a href="#引出" class="headerlink" title="引出"></a>引出</h2><ul>
<li><p>栅栏类似于闭锁（CountDownLatch），它能阻塞一组线程直到某个事件的发生。栅栏与闭锁的关键区别在于， <strong>所有的线程必须同时到达栅栏位置，才能继续执行</strong>。闭锁用于等待事件，而 <strong>栅栏用于等待其他线程</strong>。</p>
</li>
<li><p>CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。 <strong>当线程到达栅栏位置时将调用await方法，这个方法将阻塞直到所有线程都到达栅栏位置。</strong> 如果所有线程都到达栅栏位置，那么栅栏将打开，此时所有的线程都将被释放，而栅栏将被重置以便下次使用。</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> _05_AQS;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.BrokenBarrierException;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CyclicBarrier;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 10:34</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video33</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        CyclicBarrier cyclicBarrier = <span class="keyword">new</span> CyclicBarrier(<span class="number">7</span>,() -&gt; System.out.println(<span class="string">&quot;收集到7颗龙珠,召唤神龙&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">             <span class="keyword">final</span> <span class="keyword">int</span> temp = i + <span class="number">1</span>;</span><br><span class="line">             <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t收集到第&quot;</span> + temp + <span class="string">&quot;颗龙珠&quot;</span>);</span><br><span class="line">                 <span class="keyword">try</span> &#123;</span><br><span class="line">                     <span class="keyword">int</span> await = cyclicBarrier.await();</span><br><span class="line">                     System.out.println(<span class="string">&quot;还剩几个:&quot;</span> + await);</span><br><span class="line">                 &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                     e.printStackTrace();</span><br><span class="line">                 &#125; <span class="keyword">catch</span> (BrokenBarrierException e) &#123;</span><br><span class="line">                     e.printStackTrace();</span><br><span class="line">                 &#125;</span><br><span class="line">             &#125;,<span class="string">&quot;线程&quot;</span> + String.valueOf(i)).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">线程0	收集到第1颗龙珠</span><br><span class="line">线程2	收集到第3颗龙珠</span><br><span class="line">线程3	收集到第4颗龙珠</span><br><span class="line">线程1	收集到第2颗龙珠</span><br><span class="line">线程4	收集到第5颗龙珠</span><br><span class="line">线程5	收集到第6颗龙珠</span><br><span class="line">线程6	收集到第7颗龙珠</span><br><span class="line">收集到7颗龙珠,召唤神龙</span><br><span class="line">还剩几个:0</span><br><span class="line">还剩几个:6</span><br><span class="line">还剩几个:3</span><br><span class="line">还剩几个:4</span><br><span class="line">还剩几个:5</span><br><span class="line">还剩几个:1</span><br><span class="line">还剩几个:2</span><br></pre></td></tr></table></figure>

<p>可以明显的看到cyclicBarrier会阻塞所有线程，和countdownlatch不一样。</p>
<h2 id="API使用"><a href="#API使用" class="headerlink" title="API使用"></a>API使用</h2><h3 id="构造方法"><a href="#构造方法" class="headerlink" title="构造方法"></a>构造方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">CyclicBarrier</span><span class="params">(<span class="keyword">int</span> parties)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">CyclicBarrier</span><span class="params">(<span class="keyword">int</span> parties, Runnable barrierAction)</span></span></span><br></pre></td></tr></table></figure>

<ul>
<li><code>parties</code> 是参与线程的个数</li>
<li>第二个构造方法有一个 <code>Runnable</code> 参数，这个参数的意思是 *<em>最后一个到达线程要做的任务</em></li>
</ul>
<h3 id="重要方法"><a href="#重要方法" class="headerlink" title="重要方法"></a>重要方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">await</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, BrokenBarrierException</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">await</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span> <span class="keyword">throws</span> InterruptedException, BrokenBarrierException, TimeoutException</span></span><br></pre></td></tr></table></figure>

<ul>
<li>线程调用 await() <strong>表示自己已经到达栅栏</strong></li>
<li>BrokenBarrierException 表示栅栏已经被破坏，破坏的原因可能是其中一个线程 await() 时被中断或者超时</li>
</ul>
<h3 id="其他方法"><a href="#其他方法" class="headerlink" title="其他方法"></a>其他方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">reset</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>

<ul>
<li>将屏障重置为初始状态。 如果任何一方正在等待屏障，他们将返回 <strong>BrokenBarrierException</strong> 。</li>
<li>这样就可以重复利用这个屏障</li>
</ul>
<h2 id="CyclicBarrier-与-CountDownLatch-区别"><a href="#CyclicBarrier-与-CountDownLatch-区别" class="headerlink" title="CyclicBarrier 与 CountDownLatch 区别"></a>CyclicBarrier 与 CountDownLatch 区别</h2><ul>
<li><code>CountDownLatch</code> 是一次性的。 <code>CyclicBarrier</code> 是可循环利用的</li>
<li><code>CountDownLatch</code> 参与的线程的职责是不一样的，有的在倒计时，有的在等待倒计时结束。 <code>CyclicBarrier</code> 参与的线程职责是一样的</li>
</ul>
<blockquote>
<p>牛客-京东2019春招Java开发笔试卷-T27</p>
</blockquote>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/liangyihuai/article/details/83106584">https://blog.csdn.net/liangyihuai/article/details/83106584</a></p>
</blockquote>
<p>从jdk作者设计的目的来看，javadoc是这么描述它们的：</p>
<ul>
<li>CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. </li>
<li>CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.  </li>
<li>从javadoc的描述可以得出： CountDownLatch：一个或者多个线程，等待其他多个线程完成某件事情之后才能执行； CyclicBarrier：多个线程互相等待，直到到达同一个同步点，再继续一起执行。 </li>
<li>对于CountDownLatch来说，重点是“一个线程（多个线程）等待”，而其他的N个线程在完成“某件事情”之后，可以终止，也可以等待。 而对于CyclicBarrier，重点是多个线程，在任意一个线程没有完成，所有的线程都必须互相等待，然后继续一起执行。 CountDownLatch是计数器，线程完成一个记录一个，只不过计数不是递增而是递减，而CyclicBarrier更像是一个阀门，需要所有线程都到达，阀门才能打开，然后继续执行。 按照这个题目的描述等所有线程都到达了这一个阀门处，再一起执行，此题强调的是，一起继续执行，我认为 选B 比较合理！  </li>
</ul>
<ul>
<li><p>像上文中CountDownLatch的例子，main线程在等待，其余6个线程任务做完之后，main线程才苏醒干后面的事。因为countdown只会阻塞调用者，其它线程干完任务就可以干其他事。这里的调用者线程就是main线程。</p>
</li>
<li><p>像上文中CyclicBarrier的例子，是7个线程互相等待对方，7个任务都完成后，执行注册的回调任务。</p>
</li>
</ul>
<h1 id="Exchanger"><a href="#Exchanger" class="headerlink" title="Exchanger"></a>Exchanger</h1><h2 id="简介-2"><a href="#简介-2" class="headerlink" title="简介"></a>简介</h2><ul>
<li>用于两个工作线程之间交换数据的封装工具类</li>
<li>简单说就是一个线程在完成一定的事务后想与另一个线程交换数据，则 *<em>第一个先拿出数据的线程会一直等待第二个线程，直到第二个线程拿着数据到来时才能彼此交换对应数据</em></li>
</ul>
<p><code>Exchanger&lt;v&gt;&lt;/v&gt;</code> 泛型类型，其中 <strong>V 表示可交换的数据类型</strong></p>
<h2 id="简单的应用"><a href="#简单的应用" class="headerlink" title="简单的应用"></a>简单的应用</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/10/11 21:05</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExchangerTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Exchanger&lt;String&gt; exchanger = <span class="keyword">new</span> Exchanger&lt;&gt;();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; start . &quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 如果这里睡200ms的话，应该是B线程先拿出数据，然后B线程等待A线程。因为是B先给的数据，</span></span><br><span class="line"><span class="comment">                 * 所以最后A线程会先拿到B给的数据，也就是先打印</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                TimeUnit.MILLISECONDS.sleep(<span class="number">200</span>);</span><br><span class="line">                String exchange = exchanger.exchange(<span class="string">&quot;I am come from T-A&quot;</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; get value : &quot;</span> + exchange);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; end . &quot;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;,<span class="string">&quot;A&quot;</span>).start();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot; start . &quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                String exchange = exchanger.exchange(<span class="string">&quot;I am come from T-B&quot;</span>);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; get value : &quot;</span> + exchange);</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; end . &quot;</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;,<span class="string">&quot;B&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>结果：</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">A start . </span><br><span class="line">B start . </span><br><span class="line">A get value : I am come from T-B</span><br><span class="line">B get value : I am come from T-A</span><br><span class="line">B end . </span><br><span class="line">A end . </span><br></pre></td></tr></table></figure>



<h2 id="方法介绍"><a href="#方法介绍" class="headerlink" title="方法介绍"></a>方法介绍</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">exchange</span><span class="params">(V x)</span> <span class="keyword">throws</span> InterruptedException</span></span><br></pre></td></tr></table></figure>

<ul>
<li>等待另一个线程到达此交换点，然后将给定对象传输给它，接收其对象作为回报。</li>
<li>可以被打断</li>
<li>如果已经有个线程正在等待了，则直接交换数据</li>
</ul>
<h2 id="数据的分析"><a href="#数据的分析" class="headerlink" title="数据的分析"></a>数据的分析</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/10/11 21:05</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">final</span> Exchanger&lt;Object&gt; exchanger = <span class="keyword">new</span> Exchanger&lt;&gt;();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            Object Aobj = <span class="keyword">new</span> Object();</span><br><span class="line">            System.out.println(<span class="string">&quot;A将会发送：&quot;</span> + Aobj);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Object Robj = exchanger.exchange(Aobj);</span><br><span class="line">                System.out.println(<span class="string">&quot;A接收的：&quot;</span> + Robj);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;, <span class="string">&quot;A&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt; &#123;</span><br><span class="line">            Object Bobj = <span class="keyword">new</span> Object();</span><br><span class="line">            System.out.println(<span class="string">&quot;B将会发送：&quot;</span> + Bobj);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Object Robj = exchanger.exchange(Bobj);</span><br><span class="line">                System.out.println(<span class="string">&quot;B接收的：&quot;</span> + Robj);</span><br><span class="line"></span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;, <span class="string">&quot;B&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>结果</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">A将会发送：java.lang.Object@7be2d776</span><br><span class="line">B将会发送：java.lang.Object@5eca8d3a</span><br><span class="line">B接收的：java.lang.Object@7be2d776</span><br><span class="line">A接收的：java.lang.Object@5eca8d3a</span><br></pre></td></tr></table></figure>



<p><strong>从这个例子可以看出一个很严重的问题</strong>：发送的对象和接收的对象是同一个对象，可能会用严重的线程安全问题。</p>
<h1 id="ReentrantLock"><a href="#ReentrantLock" class="headerlink" title="ReentrantLock"></a>ReentrantLock</h1><h2 id="简介-3"><a href="#简介-3" class="headerlink" title="简介"></a>简介</h2><p>当多个线程需要访问某个公共资源的时候，我们知道需要通过加锁来保证资源的访问不会出问题。java提供了两种方式来加锁：</p>
<ul>
<li>一种是关键字： <code>synchronized</code>，一种是concurrent包下的基于API实现的。</li>
<li>synchronized是 JVM底层支持的，而concurrent包则是 <code>jdk</code>实现。</li>
</ul>
<h2 id="公平锁和非公平锁"><a href="#公平锁和非公平锁" class="headerlink" title="公平锁和非公平锁"></a>公平锁和非公平锁</h2><ul>
<li><p>当有线程竞争锁时，当前线程会首先尝试获得锁而不是在队列中进行排队等候，这对于那些已经在队列中排队的线程来说显得不公平，这也是非公平锁的由来</p>
</li>
<li><p>默认情况下为非公平锁。</p>
</li>
<li><p>锁的存储结构就两个东西:”双向链表” + “int类型状态”。ReenTrantLock的实现是一种自旋锁， 通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。</p>
</li>
</ul>
<h2 id="构造方法-1"><a href="#构造方法-1" class="headerlink" title="构造方法"></a>构造方法</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ReentrantLock</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ReentrantLock</span><span class="params">(<span class="keyword">boolean</span> fair)</span></span></span><br></pre></td></tr></table></figure>

<ul>
<li><code>fair</code>：该参数为true时，会尽力维持公平</li>
</ul>
<h2 id="获得锁"><a href="#获得锁" class="headerlink" title="获得锁"></a>获得锁</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lockInterruptibly</span><span class="params">()</span>  <span class="keyword">throws</span> InterruptedException</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryLock</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryLock</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span> <span class="keyword">throws</span> InterruptedException</span></span><br></pre></td></tr></table></figure>

<p><strong>lock</strong></p>
<ul>
<li>正常的获取锁，如果没有获得到锁，就会被阻塞</li>
</ul>
<p><strong>lockInterruptibly</strong></p>
<ul>
<li>获取锁，如果没有获得到锁，就会被阻塞</li>
<li>可以被打断</li>
</ul>
<p><strong>tryLock</strong></p>
<ul>
<li>如果获得到锁，返回true</li>
<li>如果没有获得到锁，返回false</li>
<li><code>timeout</code>：表示等待的时间</li>
<li><code>tryLock()</code>在获取的锁的时候，不会考虑此时是否有其他线程在等待，会破坏公平。</li>
<li>如果你希望遵守公平设置此锁，然后用 <code>tryLock(0, TimeUnit.SECONDS)</code> 这几乎是等效的（它也检测中断）。</li>
</ul>
<h2 id="释放锁"><a href="#释放锁" class="headerlink" title="释放锁"></a>释放锁</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unlock</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>

<ul>
<li>尝试释放此锁。</li>
<li>必须是锁的持有者才能释放锁</li>
</ul>
<h2 id="锁的调试"><a href="#锁的调试" class="headerlink" title="锁的调试"></a>锁的调试</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> Thread <span class="title">getOwner</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">hasQueuedThreads</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getQueueLength</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> Collection&lt;Thread&gt; <span class="title">getQueuedThreads</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>

<p><strong>getOwner</strong></p>
<ul>
<li>返回持有锁的线程</li>
</ul>
<p><strong>hasQueuedThreads</strong></p>
<ul>
<li>是否有线程在等待获取锁</li>
</ul>
<p><strong>getQueueLength</strong></p>
<ul>
<li>获取等待锁的线程数目</li>
</ul>
<p><strong>getQueuedThreads</strong></p>
<ul>
<li>返回正在等待的线程集合</li>
</ul>
<h2 id="Lock和synchronized的区别"><a href="#Lock和synchronized的区别" class="headerlink" title="Lock和synchronized的区别"></a>Lock和synchronized的区别</h2><p><strong>底层实现</strong>：</p>
<ul>
<li>Lock基于 <code>AQS</code>实现，通过state和一个CLH队列来维护锁的获取与释放</li>
<li>synchronized需要通过 <code>monitor</code>，经历一个从用户态到内核态的转变过程，更加耗时</li>
</ul>
<p><strong>其他区别</strong></p>
<table>
<thead>
<tr>
<th>synchronized</th>
<th>Lock</th>
</tr>
</thead>
<tbody><tr>
<td>是java内置关键字，在jvm层面</td>
<td>是个java类</td>
</tr>
<tr>
<td>无法判断是否获取锁的状态</td>
<td>可以判断是否获取到锁</td>
</tr>
<tr>
<td>会自动释放锁</td>
<td>需在finally中手工释放锁（unlock()方法释放锁），否则容易造成线程死锁</td>
</tr>
<tr>
<td>线程会一直等待下去</td>
<td>如果尝试获取不到锁，线程可以不用一直等待就结束</td>
</tr>
</tbody></table>
<p><strong>总结来说</strong><br>synchronized的锁可重入、不可中断、非公平。而Lock锁可重入、可判断、可公平（两者皆可）。</p>
<h1 id="Semaphore"><a href="#Semaphore" class="headerlink" title="Semaphore"></a>Semaphore</h1><h2 id="简介-4"><a href="#简介-4" class="headerlink" title="简介"></a>简介</h2><ul>
<li><p>Semaphore是一种在多线程环境下使用的设施，该设施负责协调各个线程，以<strong>保证它们能够正确、合理的使用公共资源的设施</strong>，也是操作系统中用于控制进程同步互斥的量。</p>
</li>
<li><p>Semaphore是一种计数信号量，用于管理一组资源，内部是基于AQS的共享模式。<strong>它相当于给线程规定一个量从而控制允许活动的线程数</strong>。</p>
</li>
<li><p>Semaphore用于限制可以访问某些资源（物理或逻辑的）的线程数目，他维护了一个许可证集合，有多少资源需要限制就维护多少许可证集合，假如这里有N个资源，那就对应于N个许可证，同一时刻也只能有N个线程访问。</p>
</li>
<li><p>一个线程获取许可证就调用acquire方法，用完了释放资源就调用release方法。</p>
</li>
</ul>
<p>除了JDK定义的哪些锁，Semaphore也可以定义锁。Semaphore可以做的功能相当的多，比如秒杀限流</p>
<h2 id="用Semaphore自定义Lock"><a href="#用Semaphore自定义Lock" class="headerlink" title="用Semaphore自定义Lock"></a>用Semaphore自定义Lock</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SemaphoreTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> SemaphoreLock lock = <span class="keyword">new</span> SemaphoreLock();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Thread(()-&gt;&#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    lock.lock();</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">&quot; get the lock.&quot;</span>);</span><br><span class="line">                    Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">                &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">&quot; release the lock.&quot;</span>);</span><br><span class="line">                    lock.unlock();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;).start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">        <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SemaphoreLock</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Semaphore semaphore = <span class="keyword">new</span> Semaphore(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">            semaphore.acquire();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unlock</span><span class="params">()</span>  </span>&#123;</span><br><span class="line">            semaphore.release();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>​    </p>
<p><strong>结果</strong></p>
<blockquote>
<p>Thread-0 get the lock.<br>Thread-0 release the lock.<br>Thread-1 get the lock.<br>Thread-1 release the lock.</p>
</blockquote>
<p><strong>跟synchronized的区别</strong></p>
<ul>
<li>  可以看出最大的区别就是可以控制多个线程访问多份资源，而不是只用一个线程访问一份资源</li>
</ul>
<h2 id="用Semaphore做限流"><a href="#用Semaphore做限流" class="headerlink" title="用Semaphore做限流"></a>用Semaphore做限流</h2><p>Semaphore可以控制多个线程访问多份资源，而不是只用一个线程访问一份资源，所以在限流方面也有应用。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> _05_AQS;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Semaphore;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 10:58</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video34</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Semaphore semaphore = <span class="keyword">new</span> Semaphore(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">             <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">                 <span class="keyword">try</span> &#123;</span><br><span class="line">                     semaphore.acquire();</span><br><span class="line">                     System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 进入抢购秒杀页面，准备抢小米9&quot;</span>);</span><br><span class="line">                     <span class="comment">//停3秒后离开</span></span><br><span class="line">                     <span class="keyword">try</span> &#123;</span><br><span class="line">                         TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">                     &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                         e.printStackTrace();</span><br><span class="line">                     &#125;</span><br><span class="line">                     System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 离开抢购秒杀页面，成功抢到小米9&quot;</span>);</span><br><span class="line">                 &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                     e.printStackTrace();</span><br><span class="line">                 &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                     semaphore.release();</span><br><span class="line">                 &#125;</span><br><span class="line">             &#125;,<span class="string">&quot;用户&quot;</span> + String.valueOf(i)).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">用户0	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户2	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户1	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户1	 离开抢购秒杀页面，成功抢到小米9</span><br><span class="line">用户2	 离开抢购秒杀页面，成功抢到小米9</span><br><span class="line">用户0	 离开抢购秒杀页面，成功抢到小米9</span><br><span class="line">用户4	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户3	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户5	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户3	 离开抢购秒杀页面，成功抢到小米9</span><br><span class="line">用户4	 离开抢购秒杀页面，成功抢到小米9</span><br><span class="line">用户6	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户8	 进入抢购秒杀页面，准备抢小米9</span><br><span class="line">用户5	 离开抢购秒杀页面，成功抢到小米9</span><br><span class="line">用户7	 进入抢购秒杀页面，准备抢小米9</span><br></pre></td></tr></table></figure>

<p>代码里限制了资源为3个，所以同一时间段只能有3个线程进来抢购小米9手机。</p>
<h2 id="常用API-1"><a href="#常用API-1" class="headerlink" title="常用API"></a>常用API</h2><h3 id="构造方法-2"><a href="#构造方法-2" class="headerlink" title="构造方法"></a>构造方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Semaphore</span><span class="params">(<span class="keyword">int</span> permits)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Semaphore</span><span class="params">(<span class="keyword">int</span> permits , <span class="keyword">boolean</span> fair)</span></span></span><br></pre></td></tr></table></figure>


<ul>
<li>  <code>permits</code>：同一时间可以访问资源的线程数目</li>
<li>  <code>fair</code>：尽可能的保证公平</li>
</ul>
<h3 id="重要方法-1"><a href="#重要方法-1" class="headerlink" title="重要方法"></a>重要方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>


<ul>
<li><p><code>acquire()</code>：<strong>获取一个许可证</strong>，如果许可证用完了，则陷入阻塞。可以被打断。</p>
</li>
<li><p><code>release()</code>：<strong>释放一个许可证</strong></p>
<p><code>acquire(int permits)</code><br><code>public void release(int permits)</code></p>
</li>
</ul>
<p><strong>acquire多个时，如果没有足够的许可证可用，那么当前线程将被禁用以进行线程调度</strong>，并且处于休眠状态，直到发生两件事情之一：</p>
<ul>
<li>  一些其他线程调用此信号量的一个release方法，当前线程旁边将分配许可证，并且可用许可证的数量满足此请求;</li>
<li>  要么一些其他线程interrupts当前线程。</li>
</ul>
<p><strong>release多个时，会使许可证增多，最终可能超过初始值</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> permits)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> permits,</span></span></span><br><span class="line"><span class="function"><span class="params">                          <span class="keyword">long</span> timeout,</span></span></span><br><span class="line"><span class="function"><span class="params">                          TimeUnit unit)</span></span></span><br><span class="line"><span class="function">                   <span class="keyword">throws</span> InterruptedException</span></span><br></pre></td></tr></table></figure>


<ul>
<li>  尝试去拿，<strong>拿到返回true</strong></li>
</ul>
<h3 id="其他方法-1"><a href="#其他方法-1" class="headerlink" title="其他方法"></a>其他方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">availablePermits</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>


<ul>
<li><p>返回此信号量中当前可用的许可数。</p>
<p><code>protected Collection&lt;Thread&gt; getQueuedThreads()</code><br>public final int getQueueLength()</p>
</li>
<li><p><code>getQueuedThreads</code>返回正在阻塞的线程集合</p>
</li>
<li><p><code>getQueueLength</code>返回阻塞获取的线程数</p>
<p><code>public void acquireUninterruptibly()</code><br><code>public void acquireUninterruptibly(int permits)</code></p>
</li>
<li><p>可以<code>不被打断</code>获取许可证</p>
<p><code>public int drainPermits()</code></p>
</li>
<li><p>获取当前全部的许可证目标</p>
</li>
</ul>
<h1 id="Condition"><a href="#Condition" class="headerlink" title="Condition"></a>Condition</h1><h2 id="简介-5"><a href="#简介-5" class="headerlink" title="简介"></a>简介</h2><ul>
<li>Condition主要是用于线程通信的，也就是和Object类的wait，notify有同样的功能。不过Condition的功能更加多样，Conditon可以绑定锁，实现选择性唤醒。</li>
<li>Condition和Lock搭配使用; condition必须使用<code>lock.newCondition();</code>来创建condition。必须存放在Lock中。否则抛出异常。</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> _07_LockAndCondition;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Condition;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 15:41</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述: A线程打印3次,B线程打印6次,C线程9次，持续两轮</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConditionDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ShareResource shareResource = <span class="keyword">new</span> ShareResource();</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++) &#123;</span><br><span class="line">                shareResource.print3();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;A&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++) &#123;</span><br><span class="line">                shareResource.print6();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;B&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++) &#123;</span><br><span class="line">                shareResource.print9();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;C&quot;</span>).start();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//以前是一个lock只有一个钥匙,现在是一个lock多个钥匙</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ShareResource</span></span>&#123;</span><br><span class="line">    <span class="comment">//标志位,可取值为1,2,3</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> Integer flag = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">private</span> Condition c1 = lock.newCondition();</span><br><span class="line">    <span class="keyword">private</span> Condition c2 = lock.newCondition();</span><br><span class="line">    <span class="keyword">private</span> Condition c3 = lock.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print3</span><span class="params">()</span></span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(flag != <span class="number">1</span>)&#123;</span><br><span class="line">                c1.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span> ; i++) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + (i+<span class="number">1</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            flag = <span class="number">2</span>;</span><br><span class="line">            c2.signal();<span class="comment">//唤醒2号线程</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print6</span><span class="params">()</span></span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(flag != <span class="number">2</span>)&#123;</span><br><span class="line">                c2.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span> ; i++) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + (i+<span class="number">1</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            flag = <span class="number">3</span>;</span><br><span class="line">            c3.signal();<span class="comment">//唤醒3号线程</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print9</span><span class="params">()</span></span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(flag != <span class="number">3</span>)&#123;</span><br><span class="line">                c3.await();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">9</span> ; i++) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + (i+<span class="number">1</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            flag = <span class="number">1</span>;</span><br><span class="line">            c1.signal();<span class="comment">//唤醒1号线程</span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">A	1</span><br><span class="line">A	2</span><br><span class="line">A	3</span><br><span class="line">B	1</span><br><span class="line">B	2</span><br><span class="line">B	3</span><br><span class="line">B	4</span><br><span class="line">B	5</span><br><span class="line">B	6</span><br><span class="line">C	1</span><br><span class="line">C	2</span><br><span class="line">C	3</span><br><span class="line">C	4</span><br><span class="line">C	5</span><br><span class="line">C	6</span><br><span class="line">C	7</span><br><span class="line">C	8</span><br><span class="line">C	9</span><br><span class="line">A	1</span><br><span class="line">A	2</span><br><span class="line">A	3</span><br><span class="line">B	1</span><br><span class="line">B	2</span><br><span class="line">B	3</span><br><span class="line">B	4</span><br><span class="line">B	5</span><br><span class="line">B	6</span><br><span class="line">C	1</span><br><span class="line">C	2</span><br><span class="line">C	3</span><br><span class="line">C	4</span><br><span class="line">C	5</span><br><span class="line">C	6</span><br><span class="line">C	7</span><br><span class="line">C	8</span><br><span class="line">C	9</span><br></pre></td></tr></table></figure>



<h2 id="Condition版生产者消费者"><a href="#Condition版生产者消费者" class="headerlink" title="Condition版生产者消费者"></a>Condition版生产者消费者</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 15:03</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述: 使用Lock和Condition实现</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Producer_04</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Consumer4 consumer = <span class="keyword">new</span> Consumer4();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//生产者线程A</span></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.increment();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;生产者A&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.decrement();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;消费者B&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.increment();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;生产者C&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.decrement();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;消费者D&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Consumer4</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> Integer num = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">private</span> Condition condition = lock.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">void</span> <span class="title">increment</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(num != <span class="number">0</span>)&#123;</span><br><span class="line">                condition.await();</span><br><span class="line">            &#125;</span><br><span class="line">            num++;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + num);</span><br><span class="line">            condition.signalAll();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span>  <span class="keyword">void</span> <span class="title">decrement</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span>(num == <span class="number">0</span>)&#123;</span><br><span class="line">                condition.await();</span><br><span class="line">            &#125;</span><br><span class="line">            num--;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + num);</span><br><span class="line">            condition.signalAll();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h1 id="ReentrantReadWriteLock读写锁"><a href="#ReentrantReadWriteLock读写锁" class="headerlink" title="ReentrantReadWriteLock读写锁"></a>ReentrantReadWriteLock读写锁</h1><p>读写锁的目的是为了让读 — 读之间不加锁</p>
<table>
<thead>
<tr>
<th>冲突</th>
<th>策略</th>
</tr>
</thead>
<tbody><tr>
<td>读 — 读</td>
<td>并行化</td>
</tr>
<tr>
<td>读 — 写</td>
<td>串行化</td>
</tr>
<tr>
<td>写 — 读</td>
<td>串行化</td>
</tr>
<tr>
<td>写 — 写</td>
<td>串行化</td>
</tr>
</tbody></table>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> _05_AQS;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 10:58</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video34</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ReentrantReadWriteLock lock = <span class="keyword">new</span> ReentrantReadWriteLock(<span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Lock readLock = lock.readLock();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Lock writeLock = lock.writeLock();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> List&lt;String&gt; data = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;write(),<span class="string">&quot;write-1&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;read(),<span class="string">&quot;read-1&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(()-&gt;read(),<span class="string">&quot;read-2&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            writeLock.lock();</span><br><span class="line">            data.add(<span class="string">&quot;数据XXX&quot;</span>);</span><br><span class="line">            Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;写锁释放&quot;</span>);</span><br><span class="line">            writeLock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            readLock.lock();</span><br><span class="line">            <span class="keyword">for</span> (String datum : data) &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot; 读入：&quot;</span>+datum);</span><br><span class="line">            &#125;</span><br><span class="line">            Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;读锁释放&quot;</span>);</span><br><span class="line">            readLock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">写锁释放</span><br><span class="line">read-1 读入：数据XXX</span><br><span class="line">read-2 读入：数据XXX</span><br><span class="line">读锁释放</span><br><span class="line">读锁释放</span><br></pre></td></tr></table></figure>

<p>可以看到读写-串行化，读读可以并发。</p>
<h1 id="StampedLock读写锁"><a href="#StampedLock读写锁" class="headerlink" title="StampedLock读写锁"></a>StampedLock读写锁</h1><h2 id="ReadWriteLock出现的问题"><a href="#ReadWriteLock出现的问题" class="headerlink" title="ReadWriteLock出现的问题"></a>ReadWriteLock出现的问题</h2><p>1、深入分析ReadWriteLock，会发现它有个潜在的问题：如果有线程正在读，写线程需要等待读线程释放锁后才能获取写锁，即读的过程中不允许写线程去抢锁，这是一种悲观的读锁，会出现写饥饿。</p>
<p>2、有100个线程访问某个资源，如果有99线程个需要读锁，1个线程需要写锁，此时，写的线程很难得到执行。</p>
<h2 id="StampedLock改进"><a href="#StampedLock改进" class="headerlink" title="StampedLock改进"></a>StampedLock改进</h2><p>3、StampedLock和ReadWriteLock相比，改进之处在于：<code>读的过程中也允许获取写锁后写入</code> 。这样一来，我们读的数据就可能不一致，所以，<strong>需要一点额外的代码来判断读的过程中是否有写入，这种读锁是一种乐观锁</strong>。</p>
<p>4、乐观锁的意思就是乐观地估计读的过程中大概率不会有写入，因此被称为乐观锁。反过来，悲观锁则是读的过程中拒绝有写入，也就是写入必须等待。显然乐观锁的并发效率更高，但一旦有小概率的写入导致读取的数据不一致，需要能检测出来，再读一遍就行。</p>
<h2 id="用StampedLock去悲观的读"><a href="#用StampedLock去悲观的读" class="headerlink" title="用StampedLock去悲观的读"></a>用StampedLock去悲观的读</h2><p>StampedLock可以完全实现ReadWriteLock的功能。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StampedLockDemo1</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> StampedLock stampedLock = <span class="keyword">new</span> StampedLock();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Integer DATA = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> stamp = -<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            stamp = stampedLock.writeLock();<span class="comment">// 获取写锁</span></span><br><span class="line">            DATA++;</span><br><span class="line">            System.out.println(<span class="string">&quot;写--&gt;&quot;</span> + DATA);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            stampedLock.unlockWrite(stamp); <span class="comment">// 释放写锁</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> stamp = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            stamp = stampedLock.readLock();<span class="comment">// 获取悲观读锁</span></span><br><span class="line">            System.out.println(<span class="string">&quot;读--&gt;&quot;</span> + DATA);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            stampedLock.unlockRead(stamp); <span class="comment">// 释放悲观读锁</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line">        <span class="comment">//写任务</span></span><br><span class="line">        Runnable writeTask = () -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (; ; ) &#123;</span><br><span class="line">                write();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="comment">//读任务</span></span><br><span class="line">        Runnable readTask = () -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (; ; ) &#123;</span><br><span class="line">                read();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//一个线程写，9个线程读</span></span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(writeTask);<span class="comment">//写线程要写最后</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>独线程一旦先执行，写线程很难再获得锁</p>
<blockquote>
<p>输出结果：</p>
<p>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>读–&gt;0<br>写–&gt;1</p>
</blockquote>
<h2 id="用StampedLock去乐观的读"><a href="#用StampedLock去乐观的读" class="headerlink" title="用StampedLock去乐观的读"></a>用StampedLock去乐观的读</h2><p>只需要改一下read()</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StampedLockDemo2</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> StampedLock stampedLock = <span class="keyword">new</span> StampedLock();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Integer DATA = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> stamp = -<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            stamp = stampedLock.writeLock();<span class="comment">// 获取写锁</span></span><br><span class="line">            DATA++;</span><br><span class="line">            System.out.println(<span class="string">&quot;写--&gt;&quot;</span> + DATA);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            stampedLock.unlockWrite(stamp); <span class="comment">// 释放写锁</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> stamp = stampedLock.tryOptimisticRead(); <span class="comment">// 获得一个乐观读锁</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//在这块可能会有写锁抢锁，修改数据，所以用validate检查乐观读锁后是否有其他写锁发生</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 1、在这块可能会有写锁抢锁，修改数据，所以用validate检查乐观读锁后是否有其他写锁发生</span></span><br><span class="line"><span class="comment">         * 判断执行读操作期间,是否存在写操作,如果存在则validate返回false</span></span><br><span class="line"><span class="comment">         * 2、如果有写锁抢锁，修改了数据，那么就要获取悲观锁。因为写锁在修改数据的过程中，你不能直接</span></span><br><span class="line"><span class="comment">         * 去读，只能老老实实拿到读锁再去读，才不会发生线程安全问题</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">if</span> (!stampedLock.validate(stamp)) &#123;<span class="comment">//检查乐观读锁后是否有其他写锁发生</span></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                stamp = stampedLock.readLock();<span class="comment">// 获取悲观读锁</span></span><br><span class="line">                System.out.println(<span class="string">&quot;悲观读--&gt;&quot;</span> + DATA);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                stampedLock.unlockRead(stamp); <span class="comment">// 释放悲观读锁</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;乐观读--&gt;&quot;</span> + DATA);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line">        <span class="comment">//写任务</span></span><br><span class="line">        Runnable writeTask = () -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (; ; ) &#123;</span><br><span class="line">                write();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="comment">//读任务</span></span><br><span class="line">        Runnable readTask = () -&gt; &#123;</span><br><span class="line">            <span class="keyword">for</span> (; ; ) &#123;</span><br><span class="line">                read();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//一个线程写，9个线程读</span></span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(readTask);</span><br><span class="line">        executor.submit(writeTask);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<blockquote>
<p>悲观读–&gt;704<br>写–&gt;705<br>写–&gt;706<br>写–&gt;707<br>悲观读–&gt;707<br>写–&gt;708<br>悲观读–&gt;708<br>写–&gt;709<br>写–&gt;710<br>悲观读–&gt;710<br>乐观读–&gt;710<br>乐观读–&gt;690<br>乐观读–&gt;690<br>乐</p>
</blockquote>
<h1 id="ForkJoin框架"><a href="#ForkJoin框架" class="headerlink" title="ForkJoin框架"></a>ForkJoin框架</h1><p>思想：分而治之。将一个大任务分割成若干小任务，最终汇总每个小任务的结果得到这个大任务的结果。</p>
<p><strong>举例说明</strong></p>
<p>1、我们举个例子：如果要计算一个超大数组的和，最简单的做法是用一个循环在一个线程内完成：</p>
<p>2、还有一种方法，可以把数组拆成两部分，分别计算，最后加起来就是最终结果，这样可以用两个线程并行执行：</p>
<p>3、如果拆成两部分还是很大，我们还可以继续拆，用4个线程并行执行：</p>
<p>这就是Fork/Join任务的原理：判断一个任务是否足够小。如果是，直接计算，否则，就分拆成几个小任务分别计算。这个过程可以反复“裂变”成一系列小任务。</p>
<p><strong>编码实现</strong></p>
<p><strong>整个任务流程如下所示</strong>：</p>
<ul>
<li>首先继承任务，覆写任务的执行方法</li>
<li>通过判断阈值，判断该线程是否可以执行</li>
<li>如果不能执行，则将任务继续递归分配，利用fork方法，并行执行</li>
<li>如果是有返回值的，才需要调用join方法，汇集数据。</li>
</ul>
<p><strong>主要的两个类：</strong></p>
<ul>
<li><code>RecursiveAction</code> 一个递归无结果的ForkJoinTask（没有返回值）</li>
<li><code>RecursiveTask</code> 一个递归有结果的ForkJoinTask（有返回值）</li>
</ul>
<h2 id="RecursiveTask"><a href="#RecursiveTask" class="headerlink" title="RecursiveTask"></a>RecursiveTask</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ForkJoinRecursiveTask</span>  </span>&#123;</span><br><span class="line">	<span class="comment">/* </span></span><br><span class="line"><span class="comment">	   1、分到哪种程度可以不用分了</span></span><br><span class="line"><span class="comment">	   2、也就是设置一个任务处理最大的阈值</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_THRESHOLD = <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> ForkJoinPool joinPool = <span class="keyword">new</span> ForkJoinPool();</span><br><span class="line">        ForkJoinTask&lt;Integer&gt; future = joinPool.submit(<span class="keyword">new</span> CalculatedRecursiveTask(<span class="number">0</span>, <span class="number">1000</span>));</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Integer integer = future.get();</span><br><span class="line">            System.out.println(<span class="string">&quot;执行结果：&quot;</span> + integer);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (ExecutionException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">CalculatedRecursiveTask</span> <span class="keyword">extends</span> <span class="title">RecursiveTask</span>&lt;<span class="title">Integer</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> start;<span class="comment">//任务开始的上标</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> end;<span class="comment">//任务开始的下标</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="title">CalculatedRecursiveTask</span><span class="params">(<span class="keyword">int</span> start, <span class="keyword">int</span> end)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.start = start;</span><br><span class="line">            <span class="keyword">this</span>.end = end;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> Integer <span class="title">compute</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (end - start &lt;= MAX_THRESHOLD) &#123;<span class="comment">//如果自己能处理，就自己计算</span></span><br><span class="line">                <span class="keyword">return</span> IntStream.rangeClosed(start, end).sum();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;<span class="comment">//自己处理不了，拆分任务</span></span><br><span class="line">                <span class="keyword">int</span> middle = (end + start) / <span class="number">2</span>;</span><br><span class="line">                CalculatedRecursiveTask leftTask = <span class="keyword">new</span> CalculatedRecursiveTask(start, middle);</span><br><span class="line">                CalculatedRecursiveTask rightTask = <span class="keyword">new</span> CalculatedRecursiveTask(middle + <span class="number">1</span>, end);</span><br><span class="line">				</span><br><span class="line">                <span class="comment">//分别去执行</span></span><br><span class="line">                leftTask.fork();</span><br><span class="line">                rightTask.fork();</span><br><span class="line">				</span><br><span class="line">                <span class="comment">//把返回结果合起来</span></span><br><span class="line">                <span class="keyword">return</span> leftTask.join() + rightTask.join();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>这个是有返回值的</p>
<h2 id="RecursiveAction"><a href="#RecursiveAction" class="headerlink" title="RecursiveAction"></a>RecursiveAction</h2><p>这个是没有返回值的</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ForkJoinRecursiveAction</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_THRESHOLD = <span class="number">3</span>;<span class="comment">//设置一个任务处理最大的阈值</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> AtomicInteger SUM = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        ForkJoinPool forkJoinPool = <span class="keyword">new</span> ForkJoinPool();</span><br><span class="line">		</span><br><span class="line">        forkJoinPool.submit(<span class="keyword">new</span> CalculateRecursiveAction(<span class="number">0</span>,<span class="number">1000</span>));</span><br><span class="line">		</span><br><span class="line">        <span class="comment">//任务执行需要事件，这里可以等一下</span></span><br><span class="line">        forkJoinPool.awaitTermination(<span class="number">10</span>, TimeUnit.SECONDS);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;执行结果为：&quot;</span> + SUM);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">CalculateRecursiveAction</span> <span class="keyword">extends</span> <span class="title">RecursiveAction</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> start;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> end;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="title">CalculateRecursiveAction</span><span class="params">(<span class="keyword">int</span> start, <span class="keyword">int</span> end)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.start = start;</span><br><span class="line">            <span class="keyword">this</span>.end = end;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">compute</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> ((end-start)&lt;=MAX_THRESHOLD)&#123;</span><br><span class="line">                SUM.addAndGet(IntStream.rangeClosed(start,end).sum());</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">int</span> middle = (start+end)/<span class="number">2</span>;</span><br><span class="line">                CalculateRecursiveAction leftAction = <span class="keyword">new</span> CalculateRecursiveAction(start,middle);</span><br><span class="line">                CalculateRecursiveAction rightAction = <span class="keyword">new</span> CalculateRecursiveAction(middle+<span class="number">1</span>,end);</span><br><span class="line">                leftAction.fork();</span><br><span class="line">                rightAction.fork();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p><strong>整个流程需要三个类完成</strong>：</p>
<p>1、<strong>ForkJoinPool</strong></p>
<ul>
<li><p>既然任务是被逐渐的细化的，那就需要把这些任务存在一个池子里面，这个池子就是ForkJoinPool。</p>
</li>
<li><p>它与其它的ExecutorService区别主要在于它使用**”工作窃取”**，那什么是工作窃取呢？</p>
</li>
<li><p>工作窃取：一个大任务会被划分成无数个小任务，这些任务被分配到不同的队列，这些队列有些干活干的块，有些干得慢。于是干得快的，一看自己没任务需要执行了，就去隔壁的队列里面拿去任务执行。</p>
</li>
</ul>
<p>2、<strong>ForkJoinTask</strong></p>
<p>ForkJoinTask就是ForkJoinPool里面的每一个任务。他主要有两个子类：<code>RecursiveAction</code>和<code>RecursiveTask</code>。然后通过fork()方法去分配任务执行任务，通过join()方法汇总任务结果。</p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.8/Java_concurrency/Source_code/Third_stage/0001.png">

<h2 id="小总结"><a href="#小总结" class="headerlink" title="小总结"></a>小总结</h2><ul>
<li>Fork/Join是一种基于“分治”的算法：通过分解任务，并行执行，最后合并结果得到最终结果。</li>
<li>ForkJoinPool线程池可以把一个大任务分拆成小任务并行执行，任务类必须继承自RecursiveTask或RecursiveAction。</li>
<li>使用Fork/Join模式可以进行并行计算以提高效率。</li>
</ul>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">youthlql</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://imlql.cn/post/5be45d9e.html">https://imlql.cn/post/5be45d9e.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://imlql.cn" target="_blank">风祈的时光录</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Java%E5%B9%B6%E5%8F%91/">Java并发</a><a class="post-meta__tags" href="/tags/%E5%8E%9F%E7%90%86/">原理</a><a class="post-meta__tags" href="/tags/%E6%BA%90%E7%A0%81/">源码</a></div><div class="post_share"></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="https://npm.elemecdn.com/youthlql@1.0.8/blog/wechat.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="https://npm.elemecdn.com/youthlql@1.0.8/blog/wechat.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="https://npm.elemecdn.com/youthlql@1.0.8/blog/alipay.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="https://npm.elemecdn.com/youthlql@1.0.8/blog/alipay.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/post/70c90e5d.html"><img class="prev-cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Java并发体系-第三阶段-JUC并发包-[2]</div></div></a></div><div class="next-post pull-right"><a href="/post/113a3931.html"><img class="next-cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Java并发体系-第二阶段-锁与同步-[3]</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/post/8210870.html" title="Java并发体系-第二阶段-锁与同步-[2]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-07</div><div class="title">Java并发体系-第二阶段-锁与同步-[2]</div></div></a></div><div><a href="/post/230c5bb3.html" title="Java并发体系-第二阶段-锁与同步-[1]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-06</div><div class="title">Java并发体系-第二阶段-锁与同步-[1]</div></div></a></div><div><a href="/post/113a3931.html" title="Java并发体系-第二阶段-锁与同步-[3]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-08</div><div class="title">Java并发体系-第二阶段-锁与同步-[3]</div></div></a></div><div><a href="/post/efc79183.html" title="Java并发体系-第一阶段-多线程基础知识"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-05</div><div class="title">Java并发体系-第一阶段-多线程基础知识</div></div></a></div><div><a href="/post/70c90e5d.html" title="Java并发体系-第三阶段-JUC并发包-[2]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-10</div><div class="title">Java并发体系-第三阶段-JUC并发包-[2]</div></div></a></div><div><a href="/post/92c4503d.html" title="Java并发体系-第四阶段-AQS源码解读-[1]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-26</div><div class="title">Java并发体系-第四阶段-AQS源码解读-[1]</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#AtomicXXXFieldUpdater"><span class="toc-text">AtomicXXXFieldUpdater</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">使用场景</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#CountDownLatch"><span class="toc-text">CountDownLatch</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-1"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E4%B8%80"><span class="toc-text">使用场景一</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E4%BA%8C"><span class="toc-text">使用场景二</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8API"><span class="toc-text">常用API</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BB%99%E7%A6%BB%E6%95%A3%E7%9A%84%E5%B9%B3%E8%A1%8C%E4%BB%BB%E5%8A%A1%E5%A2%9E%E5%8A%A0%E9%80%BB%E8%BE%91%E5%B1%82%E6%AC%A1%E5%85%B3%E7%B3%BB"><span class="toc-text">给离散的平行任务增加逻辑层次关系</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%A9%E7%94%A8CountDownLatch%E5%AE%9E%E7%8E%B0%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0"><span class="toc-text">利用CountDownLatch实现回调函数</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#CyclicBarrier"><span class="toc-text">CyclicBarrier</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BC%95%E5%87%BA"><span class="toc-text">引出</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#API%E4%BD%BF%E7%94%A8"><span class="toc-text">API使用</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95"><span class="toc-text">构造方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%87%8D%E8%A6%81%E6%96%B9%E6%B3%95"><span class="toc-text">重要方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E4%BB%96%E6%96%B9%E6%B3%95"><span class="toc-text">其他方法</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#CyclicBarrier-%E4%B8%8E-CountDownLatch-%E5%8C%BA%E5%88%AB"><span class="toc-text">CyclicBarrier 与 CountDownLatch 区别</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Exchanger"><span class="toc-text">Exchanger</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-2"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E5%8D%95%E7%9A%84%E5%BA%94%E7%94%A8"><span class="toc-text">简单的应用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%96%B9%E6%B3%95%E4%BB%8B%E7%BB%8D"><span class="toc-text">方法介绍</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE%E7%9A%84%E5%88%86%E6%9E%90"><span class="toc-text">数据的分析</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#ReentrantLock"><span class="toc-text">ReentrantLock</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-3"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%AC%E5%B9%B3%E9%94%81%E5%92%8C%E9%9D%9E%E5%85%AC%E5%B9%B3%E9%94%81"><span class="toc-text">公平锁和非公平锁</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95-1"><span class="toc-text">构造方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%8E%B7%E5%BE%97%E9%94%81"><span class="toc-text">获得锁</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%87%8A%E6%94%BE%E9%94%81"><span class="toc-text">释放锁</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%94%81%E7%9A%84%E8%B0%83%E8%AF%95"><span class="toc-text">锁的调试</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Lock%E5%92%8Csynchronized%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">Lock和synchronized的区别</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Semaphore"><span class="toc-text">Semaphore</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-4"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8Semaphore%E8%87%AA%E5%AE%9A%E4%B9%89Lock"><span class="toc-text">用Semaphore自定义Lock</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8Semaphore%E5%81%9A%E9%99%90%E6%B5%81"><span class="toc-text">用Semaphore做限流</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8API-1"><span class="toc-text">常用API</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95-2"><span class="toc-text">构造方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%87%8D%E8%A6%81%E6%96%B9%E6%B3%95-1"><span class="toc-text">重要方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E4%BB%96%E6%96%B9%E6%B3%95-1"><span class="toc-text">其他方法</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Condition"><span class="toc-text">Condition</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-5"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Condition%E7%89%88%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85"><span class="toc-text">Condition版生产者消费者</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#ReentrantReadWriteLock%E8%AF%BB%E5%86%99%E9%94%81"><span class="toc-text">ReentrantReadWriteLock读写锁</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#StampedLock%E8%AF%BB%E5%86%99%E9%94%81"><span class="toc-text">StampedLock读写锁</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#ReadWriteLock%E5%87%BA%E7%8E%B0%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">ReadWriteLock出现的问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#StampedLock%E6%94%B9%E8%BF%9B"><span class="toc-text">StampedLock改进</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8StampedLock%E5%8E%BB%E6%82%B2%E8%A7%82%E7%9A%84%E8%AF%BB"><span class="toc-text">用StampedLock去悲观的读</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8StampedLock%E5%8E%BB%E4%B9%90%E8%A7%82%E7%9A%84%E8%AF%BB"><span class="toc-text">用StampedLock去乐观的读</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#ForkJoin%E6%A1%86%E6%9E%B6"><span class="toc-text">ForkJoin框架</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#RecursiveTask"><span class="toc-text">RecursiveTask</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#RecursiveAction"><span class="toc-text">RecursiveAction</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8E%9F%E7%90%86"><span class="toc-text">原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B0%8F%E6%80%BB%E7%BB%93"><span class="toc-text">小总结</span></a></li></ol></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By youthlql</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a href="https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral" target="_blank" rel="noopener" class="one-pan-link-mark"><img style="position:relative;top:-3px; " src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/upyun/logo.png" align="absmiddle" width="60px" height="30px"></a><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn"><img class="icp-icon" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/icp.png"><span>鄂ICP备19028890号</span></a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">简</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">本地搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://npm.elemecdn.com/@fancyapps/ui/dist/fancybox.umd.js"></script><script src="https://npm.elemecdn.com/instant.page/instantpage.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script defer src="https://npm.elemecdn.com/jquery@latest/dist/jquery.min.js"></script></div></body></html>